package top.jfunc.common.utils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Supplier;

/**
 * 保存内存值，超时获取时刷新
 * 适合用于在内存中缓存数据库数值，不必每次都去查询数据库
 * @author xiongshiyan
 * @param <T> 保持在内存里面的值
 */
public class MemoryRefresher<T> implements Supplier<T>{
    /**
     * 保存所有的实例，用于invalidate
     */
    private static final List<MemoryRefresher<?>> MEMORY_REFRESHER_LIST = new ArrayList<>();
    /**
     * 默认失效时间10分钟
     */
    public static final long DEFAULT_REFRESH_TIMEOUT = 600_000L; // 10m

    /**
     * 实际的数据获取器
     */
    private final Supplier<T> dataGetter;

    /**
     * 保存每次刷新的值，也就是你需要获取的值
     */
    private volatile T t;

    /**
     * 上次更新时间，超时后重新获取
     */
    private volatile long lastUpdateAt = 0L;
    /**
     * 更新超时时间
     */
    private long refreshTimeoutInMillis;
    /**
     * 是否允许更新，某些情况下可以关闭
     */
    private boolean refreshEnabled = true;

    public MemoryRefresher(Supplier<T> dataGetter) {
        this(dataGetter, DEFAULT_REFRESH_TIMEOUT);
    }
    public MemoryRefresher(long refreshTimeoutInMillis, Supplier<T> dataGetter) {
        this(dataGetter, refreshTimeoutInMillis);
    }
    public MemoryRefresher(Supplier<T> dataGetter, long refreshTimeoutInMillis) {
        this.dataGetter = Objects.requireNonNull(dataGetter);
        this.refreshTimeoutInMillis = refreshTimeoutInMillis;

        MEMORY_REFRESHER_LIST.add(this);
    }

    /**
    * 设置 刷新超时时间
    * @param refreshTimeoutInMillis 刷新{@link #refreshTimeoutInMillis} 的间隔时间
    */
    public MemoryRefresher<T> setRefreshTimeout(long refreshTimeoutInMillis) {
        if (refreshTimeoutInMillis < 0) {
            throw new IllegalArgumentException("超时时间不能小于0");
        }
        this.refreshTimeoutInMillis = refreshTimeoutInMillis;
        return this;
    }

    /**
     * 设置需不需要在{@link #refreshTimeoutInMillis 一段时间}之后刷新状态
     */
    public MemoryRefresher<T> disableRefresh() {
        this.refreshEnabled = false;
        return this;
    }

    public T get() {
        if (needRefresh()) {
            synchronized(this) {
                if (needRefresh()) {
                    refresh();
                }
            }
        }
        return this.t;
    }
    public T getOrDefault(T defaultValue) {
        try {
            return get();
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * 版本兼容，提供老版本的方法，实际直接调用get
     */
    public T getData(){
        return get();
    }

    private boolean needRefresh() {
        return this.t == null
                || (refreshEnabled && System.currentTimeMillis() - lastUpdateAt >= refreshTimeoutInMillis);
    }

    /**
     * 刷新缓存
     */
    public void refresh(){
        this.t = dataGetter.get();
        this.lastUpdateAt = System.currentTimeMillis();
    }

    /**
     * 使配置无效，下次获取的时候必然去实际获取得到最新的值
     */
    public void invalidate(){
        this.lastUpdateAt = 0L;
    }

    /**
     * 使系统中所有的额实例缓存都失效，下次请求重新获取
     */
    public static void invalidateAll(){
        MEMORY_REFRESHER_LIST.forEach(MemoryRefresher::invalidate);
    }

    /**
     * 立即刷新所有的实例
     */
    public static void refreshAll(){
        MEMORY_REFRESHER_LIST.forEach(MemoryRefresher::refresh);
    }
}
